import numpy as np # 导入数组计算库以执行等额本息推导
import pandas as pd # 导入表格库以组织逐月时间序列
import matplotlib.pyplot as plt # 导入绘图库以显示月度构成曲线
def amortize(principal,annual_rate,years): # 定义同口径等额本息摊还函数
months=years*12 # 把贷款年限换算为总月数
monthly_rate=annual_rate/12 # 把年利率换算为月利率
payment=principal*monthly_rate*(1+monthly_rate)**months/((1+monthly_rate)**months-1) # 按标准公式计算固定月供
balance=principal # 初始化剩余本金
rows=[] # 初始化逐月检查记录
for month in range(1,months+1): # 逐月计算本金与利息构成
interest=balance*monthly_rate # 计算当月利息
principal_paid=payment-interest if month<months else balance # 末期用剩余本金消除浮点尾差
balance=max(0.0,balance-principal_paid) # 更新非负剩余本金
rows.append((month,payment,principal_paid,interest,balance)) # 保存当月完整状态
return pd.DataFrame(rows,columns=['月序','月供','本金','利息','剩余本金']) # 返回标准化月度表
base=amortize(1_000_000,.049,30) # 计算100万元、4.9%、30年基准情景
assert np.allclose(base['本金']+base['利息'],base['月供'],atol=1e-6) and np.isclose(base.iloc[-1]['剩余本金'],0.0) # 核对组成守恒与余额归零
fig,axes=plt.subplots(1,2,figsize=(11,4.2)) # 创建构成与余额双面板
axes[0].plot(base['月序'],base['本金'],label='本金'); axes[0].plot(base['月序'],base['利息'],label='利息') # 绘制逐月本金与利息
axes[1].plot(base['月序'],base['剩余本金'],label='4.9%余额',color='#007A86') # 绘制基准余额轨迹
axes[0].set(xlabel='还款月份(月)',ylabel='每月金额(元)',title='等额本息月供构成'); axes[1].set(xlabel='还款月份(月)',ylabel='剩余本金(元)',title='余额轨迹') # 标明轴、单位与图题
axes[0].legend(); axes[1].legend(); plt.tight_layout(); plt.show() # 显示便于核对图例与曲线
print({'月供':round(base.iloc[0]['月供'],2),'累计利息':round(base['利息'].sum(),2),'末期余额':base.iloc[-1]['剩余本金']}) # 输出基准数值结果